Coverage Report

Created: 2025-05-07 21:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
D:\a\tools.proto\tools.proto\compiler\src\gen\rust\util.rs
Line
Count
Source
1
// Copyright (c) 2024, BlockProject 3D
2
//
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without modification,
6
// are permitted provided that the following conditions are met:
7
//
8
//     * Redistributions of source code must retain the above copyright notice,
9
//       this list of conditions and the following disclaimer.
10
//     * Redistributions in binary form must reproduce the above copyright notice,
11
//       this list of conditions and the following disclaimer in the documentation
12
//       and/or other materials provided with the distribution.
13
//     * Neither the name of BlockProject 3D nor the names of its contributors
14
//       may be used to endorse or promote products derived from this software
15
//       without specific prior written permission.
16
//
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
use crate::compiler::message::{Field, FieldType, Message};
30
use crate::compiler::structure::FixedFieldType;
31
use crate::compiler::util::types::TypeMapper;
32
use crate::gen::base::map::TypePathMapper;
33
use crate::gen::template::Template;
34
use crate::model::protocol::Endianness;
35
use itertools::Itertools;
36
use std::borrow::Cow;
37
38
macro_rules! gen_value_type {
39
    ($prefix: literal, $ty: expr, $suffix: literal) => {
40
        match $ty {
41
            FixedFieldType::Int8 => concat!($prefix, "i8", $suffix),
42
            FixedFieldType::Int16 => concat!($prefix, "i16", $suffix),
43
            FixedFieldType::Int32 => concat!($prefix, "i32", $suffix),
44
            FixedFieldType::Int64 => concat!($prefix, "i64", $suffix),
45
            FixedFieldType::UInt8 => concat!($prefix, "u8", $suffix),
46
            FixedFieldType::UInt16 => concat!($prefix, "u16", $suffix),
47
            FixedFieldType::UInt32 => concat!($prefix, "u32", $suffix),
48
            FixedFieldType::UInt64 => concat!($prefix, "u64", $suffix),
49
            FixedFieldType::Float32 => concat!($prefix, "f32", $suffix),
50
            FixedFieldType::Float64 => concat!($prefix, "f64", $suffix),
51
            FixedFieldType::Bool => concat!($prefix, "bool", $suffix),
52
        }
53
    };
54
}
55
56
pub struct Generic<'a> {
57
    pub name: Cow<'a, str>,
58
    pub default: Option<Cow<'a, str>>,
59
}
60
61
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
62
pub enum Lifetime {
63
    None,
64
    Anonymous,
65
    Named,
66
}
67
68
pub struct Generics<T> {
69
    lifetime: Lifetime,
70
    data: T,
71
}
72
73
impl<T> Generics<T> {
74
109
    pub fn new(lifetime: Lifetime, data: T) -> Self {
75
109
        Self { lifetime, data }
76
109
    }
77
}
78
79
109
fn _to_string<'a>(mut generics: impl Iterator<Item = Cow<'a, str>>, lifetime: Lifetime) -> Cow<'a, str> {
80
109
    if let Some(
value20
) = generics.next() {
  Branch (80:12): [True: 16, False: 60]
  Branch (80:12): [True: 4, False: 29]
  Branch (80:12): [Folded - Ignored]
81
20
        let str = generics.join(", ");
82
20
        match (str.is_empty(), lifetime) {
83
4
            (true, Lifetime::None) => format!("<{}>", value).into(),
84
0
            (false, Lifetime::None) => format!("<{}, {}>", value, str).into(),
85
12
            (true, Lifetime::Named) => format!("<'a, {}>", value).into(),
86
0
            (false, Lifetime::Named) => format!("<'a, {}, {}>", value, str).into(),
87
4
            (true, Lifetime::Anonymous) => format!("<'_, {}>", value).into(),
88
0
            (false, Lifetime::Anonymous) => format!("<'_, {}, {}>", value, str).into(),
89
        }
90
89
    } else if lifetime == Lifetime::Named {
  Branch (90:15): [True: 29, False: 31]
  Branch (90:15): [True: 27, False: 2]
  Branch (90:15): [Folded - Ignored]
91
56
        Cow::Borrowed("<'a>")
92
33
    } else if lifetime == Lifetime::Anonymous {
  Branch (92:15): [True: 0, False: 31]
  Branch (92:15): [True: 0, False: 2]
  Branch (92:15): [Folded - Ignored]
93
0
        Cow::Borrowed("<'_>")
94
    } else {
95
33
        Cow::Borrowed("")
96
    }
97
109
}
98
99
impl<'a, T: Iterator<Item = Generic<'a>>> Generics<T> {
100
76
    pub fn into_string(self) -> Cow<'a, str> {
101
76
        let generics = self.data.map(|v| match 
&v.default16
{
102
0
            None => v.name,
103
16
            Some(_) => v.name,
104
16
        });
105
76
        _to_string(generics, self.lifetime)
106
76
    }
107
108
33
    pub fn into_string_with_defaults(self) -> Cow<'a, str> {
109
33
        let generics = self.data.map(|v| match 
&v.default4
{
110
0
            None => v.name,
111
4
            Some(v1) => format!("{}={}", v.name, v1).into(),
112
4
        });
113
33
        _to_string(generics, self.lifetime)
114
33
    }
115
}
116
117
pub struct RustUtils;
118
119
impl RustUtils {
120
109
    fn _gen_generics<'a, T: TypeMapper>(
121
109
        msg: &'a Message,
122
109
        type_path_map: &'a TypePathMapper<T>,
123
109
        lifetime: Lifetime,
124
109
    ) -> Generics<impl Iterator<Item = Generic<'a>>> {
125
209
        let 
unions109
=
msg.fields.iter()109
.
filter_map109
(|v| match &v.ty {
126
20
            FieldType::Union(u) => Some(Generic {
127
20
                name: format!("T{}", v.name).into(),
128
20
                default: Some(format!("{}<'a>", type_path_map.get(&u.r)).into()),
129
20
            }),
130
189
            _ => None,
131
209
        });
132
109
        Generics::new(lifetime, unions)
133
109
    }
134
135
43
    pub fn get_generics_for_write<'a, T: TypeMapper>(
136
43
        msg: &'a Message,
137
43
        type_path_map: &'a TypePathMapper<T>,
138
43
        lifetime: Lifetime,
139
43
    ) -> Generics<impl Iterator<Item = Generic<'a>>> {
140
89
        let 
has_lifetime43
=
msg.fields.iter()43
.
any43
(|v| matches!(v.ty, FieldType::Union(_)));
141
43
        Self::_gen_generics(msg, type_path_map, if has_lifetime { 
lifetime12
} else {
Lifetime::None31
})
  Branch (141:52): [True: 12, False: 31]
  Branch (141:52): [Folded - Ignored]
142
43
    }
143
144
66
    pub fn get_generics<'a, T: TypeMapper>(
145
66
        msg: &'a Message,
146
66
        type_path_map: &'a TypePathMapper<T>,
147
66
    ) -> Generics<impl Iterator<Item = Generic<'a>>> {
148
66
        let has_lifetime = msg.fields.iter().any(|v| 
{64
149
0
            matches!(
150
64
                v.ty,
151
                FieldType::Ref(_)
152
                    | FieldType::Buffer
153
                    | FieldType::SizedBuffer(_)
154
                    | FieldType::FixedContainer(_)
155
                    | FieldType::Union(_)
156
                    | FieldType::Container(_)
157
                    | FieldType::SizedContainer(_)
158
                    | FieldType::Payload
159
            )
160
64
        });
161
66
        Self::_gen_generics(
162
66
            msg,
163
66
            type_path_map,
164
66
            if has_lifetime { 
Lifetime::Named64
} else {
Lifetime::None2
},
  Branch (164:16): [True: 64, False: 2]
  Branch (164:16): [Folded - Ignored]
165
        )
166
66
    }
167
}
168
169
impl crate::gen::base::structure::Utilities for RustUtils {
170
1.22k
    fn get_field_type(field_type: FixedFieldType) -> &'static str {
171
1.22k
        
gen_value_type!96
("", field_type, "")
172
1.22k
    }
173
174
200
    fn get_fragment_name(field: &crate::compiler::structure::Field) -> &'static str {
175
200
        let raw_field_type = field.ty.as_fixed().unwrap().bits_type;
176
200
        let raw_field_byte_size = raw_field_type.get_byte_size();
177
200
        match raw_field_byte_size != field.loc.byte_size {
178
12
            true => "unaligned",
179
188
            false => "aligned",
180
        }
181
200
    }
182
183
64
    fn get_bit_codec_inline(endianness: Endianness) -> &'static str {
184
64
        match endianness {
185
48
            Endianness::Little => "<bp3d_proto::codec::BitCodecLE as bp3d_proto::codec::BitCodec>",
186
16
            Endianness::Big => "<bp3d_proto::codec::BitCodecBE as bp3d_proto::codec::BitCodec>",
187
        }
188
64
    }
189
190
136
    fn get_byte_codec_inline(endianness: Endianness) -> &'static str {
191
136
        match endianness {
192
136
            Endianness::Little => "<bp3d_proto::codec::ByteCodecLE as bp3d_proto::codec::ByteCodec>",
193
0
            Endianness::Big => "<bp3d_proto::codec::ByteCodecBE as bp3d_proto::codec::ByteCodec>",
194
        }
195
136
    }
196
197
12
    fn get_byte_codec(endianness: Endianness) -> &'static str {
198
12
        match endianness {
199
12
            Endianness::Little => "bp3d_proto::codec::ByteCodecLE",
200
0
            Endianness::Big => "bp3d_proto::codec::ByteCodecBE",
201
        }
202
12
    }
203
}
204
205
impl crate::gen::base::message::Utilities for RustUtils {
206
139
    fn get_value_type(endianness: Endianness, ty: FixedFieldType) -> &'static str {
207
139
        match endianness {
208
139
            Endianness::Little => 
gen_value_type!0
("bp3d_proto::message::util::ValueLE<", ty, ">"),
209
0
            Endianness::Big => gen_value_type!("bp3d_proto::message::util::ValueBE<", ty, ">"),
210
        }
211
139
    }
212
213
10
    fn get_value_type_inline(endianness: Endianness, ty: FixedFieldType) -> &'static str {
214
10
        match endianness {
215
10
            Endianness::Little => 
gen_value_type!0
("bp3d_proto::message::util::ValueLE::<", ty, ">"),
216
0
            Endianness::Big => gen_value_type!("bp3d_proto::message::util::ValueBE::<", ty, ">"),
217
        }
218
10
    }
219
220
10
    fn gen_struct_ref_type(type_name: &str) -> String {
221
10
        format!("{}<&'a [u8]>", type_name)
222
10
    }
223
224
3
    fn gen_message_ref_type(type_name: &str) -> String {
225
3
        format!("{}<'a>", type_name)
226
3
    }
227
}
228
229
154
pub fn gen_where_clause<T: TypeMapper>(
230
154
    template: &Template,
231
154
    field: &Field,
232
154
    type_path_map: &TypePathMapper<T>,
233
154
    function: &str,
234
154
) -> String {
235
154
    match &field.ty {
236
14
        FieldType::Union(v) => template
237
14
            .scope()
238
14
            .var("name", &field.name)
239
14
            .var("type_name", type_path_map.get(&v.r))
240
14
            .var("discriminant_type", type_path_map.get(&v.r.discriminant.root))
241
14
            .render(function, &["where"])
242
14
            .unwrap(),
243
140
        _ => "".into(),
244
    }
245
154
}